package com.kmxd.ams.app.archive;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kmxd.ams.client.archive.IArchiveSealSvc;
import com.kmxd.ams.client.archive.IArchiveTypeSvc;
import com.kmxd.ams.client.archive.dto.*;
import com.kmxd.ams.client.archive.vo.ArchiveSealListVO;
import com.kmxd.ams.client.archive.vo.ArchiveSealVO;
import com.kmxd.ams.client.archive.vo.ArchiveTypeVO;
import com.kmxd.ams.client.arrange.IDocumentSvc;
import com.kmxd.ams.client.oss.IEfileRecordSvc;
import com.kmxd.ams.client.oss.vo.EfileRecordListVO;
import com.kmxd.ams.client.oss.vo.EfileRecordVO;
import com.kmxd.ams.client.system.ISysConfigSvc;
import com.kmxd.ams.client.system.ISysFondsSvc;
import com.kmxd.ams.core.common.constant.ConfigConst;
import com.kmxd.ams.core.common.query.QueryGen;
import com.kmxd.ams.core.oss.template.OssTemplate;
import com.kmxd.ams.core.util.DynamicTableNameUtil;
import com.kmxd.ams.core.util.IdUtil;
import com.kmxd.ams.core.util.SecurityUtil;
import com.kmxd.ams.infra.archive.entity.ArchiveSeal;
import com.kmxd.ams.infra.archive.mapper.ArchiveSealMapper;
import com.kmxd.ams.infra.arrange.base.BaseBO;
import com.kmxd.ams.infra.arrange.entity.Document;
import com.kmxd.ams.infra.seal.service.SealUtil;
import com.kmxd.ams.infra.system.entity.SysFonds;
import com.kmxd.ams.infra.utils.EfileTableNameUtil;
import java.awt.*;
import java.io.File;
import java.util.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;

/**
 * 档号章设置 服务实现类
 *
 * @author ZuoLG
 * @since 2023-09-11
 */
@Service
@AllArgsConstructor
public class ArchiveSealSvcImpl extends ServiceImpl<ArchiveSealMapper, ArchiveSeal>
    implements IArchiveSealSvc {

  private IEfileRecordSvc efileRecordSvc;
  private IArchiveTypeSvc archiveTypeSvc;
  private OssTemplate ossTemplate;
  private IDocumentSvc documentSvc;
  private final SealUtil sealUtil;
  private final ISysConfigSvc sysConfigSvc;
  private final EfileTableNameUtil tableNameUtil;

  public String getSaveMode() {
    String archSeal = sysConfigSvc.getConfigContentByKey(ConfigConst.OSS_ARCH_SEAL);
    if (StrUtil.isNotBlank(archSeal) && JSONUtil.isTypeJSON(archSeal)) {
      JSONObject sealSetting = JSONUtil.parseObj(archSeal);
      return sealSetting.get("file_save_mode", null);
    }
    return null;
  }

  @Override
  public Page<ArchiveSealListVO> selectPage(Page reqPage, ArchiveSealQueryDTO req) {
    LambdaQueryWrapper<ArchiveSeal> queryWrapper =
        QueryGen.init(new QueryWrapper<ArchiveSeal>(), req).lambda();
    Page<ArchiveSeal> page = baseMapper.selectPage(reqPage, queryWrapper);
    Page<ArchiveSealListVO> voPage = BeanUtil.copyProperties(page, Page.class);
    voPage.setRecords(BeanUtil.copyToList(page.getRecords(), ArchiveSealListVO.class));
    return voPage;
  }

  @Override
  public List<ArchiveSealListVO> selectList(ArchiveSealQueryDTO req) {
    LambdaQueryWrapper<ArchiveSeal> queryWrapper =
        QueryGen.init(new QueryWrapper<ArchiveSeal>(), req).lambda();
    List<ArchiveSeal> list = baseMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, ArchiveSealListVO.class);
  }


  @Override
  @Transactional(rollbackFor = Exception.class)
  public void add(ArchiveSealAddDTO req) {
    ArchiveSeal entity = BeanUtil.copyProperties(req, ArchiveSeal.class);
    baseMapper.insert(entity);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void edit(ArchiveSealEditDTO req) {
    ArchiveSeal entity = BeanUtil.copyProperties(req, ArchiveSeal.class);
    if (ObjectUtil.isNotEmpty(req.getStatus())) {
      // 修改当前门类其他不可用
      LambdaUpdateWrapper<ArchiveSeal> updateWrapper = Wrappers.lambdaUpdate();
      updateWrapper.in(ArchiveSeal::getArchTypeId, entity.getArchTypeId());
      updateWrapper.set(ArchiveSeal::getStatus, 0);
      this.update(updateWrapper);
    }

    ArchiveTypeVO archiveType = archiveTypeSvc.view(entity.getArchTypeId());
    entity.setArchType(archiveType.getName());
    entity.setSort(1);
    entity.setStatus(BooleanUtil.isTrue(req.getStatus()) ? true : false);
    this.saveOrUpdate(entity);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void remove(String ids) {
    Set<Long> idList = IdUtil.split(ids);
    this.baseMapper.deleteBatchIds(idList);
  }

  @Override
  public ArchiveSealVO view(ArchSealDTO req) {
    if (ObjectUtil.isNotEmpty(req.getId())) {
      ArchiveSeal entity = baseMapper.selectById(req.getId());
      return BeanUtil.copyProperties(entity, ArchiveSealVO.class);
    }
    if (ObjectUtil.isNotEmpty(req.getArchTypeId())) {
      ArchiveSeal entity = getSealByArchType(req.getArchTypeId());
      return BeanUtil.copyProperties(entity, ArchiveSealVO.class);
    }
    ArchiveSealVO archiveSeal = new ArchiveSealVO();
    archiveSeal.setComId(SecurityUtil.getCropId());
    archiveSeal.setFondsId(SecurityUtil.getFondsId());
    archiveSeal.setEnableSeal(1);
    archiveSeal.setEnableNum(0);
    return archiveSeal;
  }

  @Override
  public ArchiveSeal getSealByArchType(Long archTypeId) {
    LambdaQueryWrapper<ArchiveSeal> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.eq(ArchiveSeal::getArchTypeId, archTypeId);
    queryWrapper.eq(ArchiveSeal::getStatus, 1);
    List<ArchiveSeal> list = baseMapper.selectList(queryWrapper);
    return list.stream().findFirst().orElse(null);
  }

  @Override
  public File getSeal(ArchSealDTO req) {
    if (ObjectUtil.isNotEmpty(req.getEid())) {
      // 电子文件ID
      EfileRecordVO efile = efileRecordSvc.view(req.getEid());
      ArchiveTypeVO archiveType = archiveTypeSvc.view(efile.getArchTypeId());
      // 获取当前使用的档号章信息
      ArchiveSeal archSeal = getSealByArchType(efile.getArchTypeId());
      if (ObjectUtil.isEmpty(archSeal)) {
        return null;
      }
      if (StrUtil.isNotBlank(req.getNumSetting()) && JSONUtil.isTypeJSON(req.getNumSetting())) {
        archSeal.setNumSetting(req.getNumSetting());
      }
      if (StrUtil.isNotBlank(req.getSealSetting()) && JSONUtil.isTypeJSON(req.getSealSetting())) {
        archSeal.setSealSetting(req.getSealSetting());
      }

      Document reqDoc = new Document();
      reqDoc.setTableId(archiveType.getDocTableId());
      reqDoc.setArchTypeId(archiveType.getId());
      reqDoc.setId(efile.getArchId());
      DynamicTableNameUtil.setTableName(archiveType.getDocTableId());
      Document doc = documentSvc.view(reqDoc);

      String srcPath = ossTemplate.getManagePath(efile.getDefPath());
      if (StrUtil.isNotBlank(efile.getShowFilePath())) {
        srcPath = srcPath + efile.getShowFilePath();
      } else {
        // 如果是pdf或者ofd允许使用转换前文件
        if (StrUtil.equals("ofd", efile.getExt()) || StrUtil.equals("pdf", efile.getExt())) {
          srcPath = srcPath + efile.getSaveFileName();
        }
      }
      // 如果文件不存在，则返回空文件
      if (!FileUtil.exist(srcPath)) {
        return null;
      }
      String titleName = efile.getTitle().replace("." + efile.getExt(), "");
      String titleCode = StrUtil.isNotBlank(doc.getArchCode()) ? doc.getArchCode() : titleName;
      File file = sealUtil.init().genSeal(archSeal, titleCode, srcPath, doc);

      // 档号章配置需要写文件
      if (ObjectUtil.equals("1", getSaveMode())) {
        try {
          String newPath = ossTemplate.getOcrPath(efile.getDefPath()) + efile.getShowFilePath();
          FileUtil.copy(file, FileUtil.file(newPath), true);
        } catch (Exception ex) {
          ex.printStackTrace();
          log.error("写文件异常，不影响档号章使用！" + ex.getMessage());
        }
      }
      return file;
    } else {
      try {
        Document doc = new Document();
        doc.setYear(new Date().getYear());
        doc.setFondsCode("全宗号");
        doc.setDocSequence(1);
        doc.setOrgFunction("机构问题");
        doc.setRetentionPeriod("30年");
        doc.setPageNum(99);

        ArchiveSeal archSeal = BeanUtil.copyProperties(req, ArchiveSeal.class);
        String title = "ofd_preview_file.ofd";

        String filePath = ossTemplate.getTempPath() + ossTemplate.separator() + title;
        File ofdFile = new File(filePath);
        File file = ResourceUtils.getFile("classpath:templete/" + title);
        FileUtil.copy(file, ofdFile, true);
        return sealUtil.init().genSeal(archSeal, title, filePath, doc);
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
    return null;
  }

  @Override
  public File exportSealFile(ExportSealDTO req) {
    if (ObjectUtil.isEmpty(req.getArchTypeId()) || req.getArchIds().isEmpty()) {
      return null;
    }
    ArchiveTypeVO archiveType = archiveTypeSvc.view(req.getArchTypeId());
    ISysFondsSvc sysFondsSvc = SpringUtil.getBean(ISysFondsSvc.class);
    SysFonds sysFonds = sysFondsSvc.getById(archiveType.getFondsId());
    String tableName = tableNameUtil.getTableName(sysFonds);
    DynamicTableNameUtil.setTableName(tableName);
    List<EfileRecordListVO> efiles =
        efileRecordSvc.selectListByDocIds(archiveType.getId(), req.getArchIds());
    // 获取当前使用的档号章信息
    ArchiveSeal archSeal = getSealByArchType(req.getArchTypeId());

    String idsStr =
        req.getArchIds().stream().map(i -> i.toString()).collect(Collectors.joining(","));
    DynamicTableNameUtil.setTableName(archiveType.getDocTableId());
    BaseBO baseBO = new BaseBO();
    baseBO.setArchTypeId(req.getArchTypeId());
    baseBO.setTableId(archiveType.getDocTableId());
    baseBO.setDocIds(idsStr);
    List<Document> docList = documentSvc.selectListByIds(baseBO);
    // 条目大于100 不允许下载
    if (docList.size() > 100) {
      return null;
    }

    List<File> fileList = Lists.newArrayList();
    for (Document doc : docList) {
      List<EfileRecordListVO> files =
          efiles.stream()
              .filter(x -> ObjectUtil.equals(doc.getId(), x.getArchId()))
              .collect(Collectors.toList());

      EfileRecordListVO efile =
          files.stream()
              .sorted(Comparator.comparing(EfileRecordListVO::getSort))
              .findFirst()
              .orElse(null);

      if (ObjectUtil.isNotEmpty(efile)) {
        String srcPath = ossTemplate.getManagePath(efile.getDefPath());
        if (StrUtil.isNotBlank(efile.getShowFilePath())) {
          srcPath = srcPath + efile.getShowFilePath();
        } else {
          // 如果是pdf或者ofd允许使用转换前文件
          if (StrUtil.equals("ofd", efile.getExt()) || StrUtil.equals("pdf", efile.getExt())) {
            srcPath = srcPath + efile.getSaveFileName();
          }
        }
        // 如果文件不存在，则返回空文件
        if (!FileUtil.exist(srcPath)) {
          return null;
        }
        String titleName = efile.getTitle().replace("." + efile.getExt(), "");
        String titleCode = StrUtil.isNotBlank(doc.getArchCode()) ? doc.getArchCode() : titleName;
        File file = sealUtil.init().genSeal(archSeal, titleCode, srcPath, doc);
        if (ObjectUtil.isNotNull(file) && FileUtil.exist(file)) {
          fileList.add(file);
        }
      }

      List<EfileRecordListVO> otherFile =
          files.stream()
              .filter(x -> ObjectUtil.notEqual(x.getId(), efile.getId()))
              .collect(Collectors.toList());

      for (EfileRecordListVO recordList : otherFile) {
        String srcPath = ossTemplate.getManagePath(recordList.getDefPath());
        if (StrUtil.isNotBlank(recordList.getShowFilePath())) {
          srcPath = srcPath + recordList.getShowFilePath();
        } else {
          // 如果是pdf或者ofd允许使用转换前文件
          if (StrUtil.equals("ofd", recordList.getExt())
              || StrUtil.equals("pdf", recordList.getExt())) {
            srcPath = srcPath + recordList.getSaveFileName();
          }
        }
        // 如果文件不存在，则返回空文件
        if (FileUtil.exist(srcPath)) {
          fileList.add(FileUtil.file(srcPath));
        }
      }
    }
    if (fileList.isEmpty()) {
      return null;
    }
    // 打包数据
    File[] files = fileList.stream().toArray(File[]::new);
    String pathYear = DateUtil.format(DateUtil.date(), "yyyy/MM/dd");
    String yearName = DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_MS_PATTERN);
    String zipPath =
        ossTemplate.getTempPath()
            + ossTemplate.separator()
            + pathYear
            + ossTemplate.separator()
            + StrUtil.format("archiving_seal_{}.zip", yearName);
    File zipFile = FileUtil.file(zipPath);
    ZipUtil.zip(zipFile, false, files);

    // 循环删除文件
    try {
      CompletableFuture.runAsync(
          () -> {
            for (File file : fileList) {
              try {
                FileUtil.del(file);
              } catch (Exception e) {
              }
            }
          });
    } catch (Exception e) {
      e.printStackTrace();
      log.error("删除档号章临时文件异常：" + e.getMessage());
    }

    return zipFile;
  }

  /**
   * 查找归档章文件
   *
   * @return
   */
  private EfileRecordListVO getEfile(List<EfileRecordListVO> efiles, Document doc) {
    List<EfileRecordListVO> files =
        efiles.stream()
            .filter(x -> ObjectUtil.equals(doc.getId(), x.getArchId()))
            .collect(Collectors.toList());

    return files.stream()
        .sorted(Comparator.comparing(EfileRecordListVO::getSort))
        .findFirst()
        .orElse(null);
  }
}
